﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Pibby.Core.Feeds
{
	public class RssFeedReader
	{
		#region Xml Constants

		const string RssNode = "rss";
		const string ChannelNode = "channel";
		const string TitleNode = "title";
		const string LinkNode = "link";
		const string DescriptionNode = "description";
		const string CopyrightNode = "copyright";
		const string PubDateNode = "pubdate";
		const string ImageNode = "image";
		const string ItunesImageNode = "itunes:image";
		const string ItemNode = "item";
		const string UrlNode = "url";
		const string HrefAttr = "href";
		const string VersionAttr = "version";


		#endregion

		/* Alt
		 *
		 *     			XDocument doc = XDocument.Load(url);

    			// RSS/Channel/item
    			var entries = from item in doc.Root.Descendants().First(i => i.Name.LocalName == Feed.ChannelNode).Elements().Where(i => i.Name.LocalName == Feed.ItemNode)
    						  select new Item
    						  {
    							  //FeedType = FeedType.RSS,
								  Content = item.Elements().First(i => i.Name.LocalName == Feed.DescriptionNode).Value,
    							  Link = item.Elements().First(i => i.Name.LocalName == Feed.LinkNode).Value,
    							  PublicationDate = ParseDate(item.Elements().First(i => i.Name.LocalName == Feed.PubDateNode).Value),
    							  Title = item.Elements().First(i => i.Name.LocalName == Feed.TitleNode).Value
    						  };

				feed = new Feed(entries.ToList());

		 */

		public Feed Read(XmlReader xmlReader)
		{
			if (xmlReader == null)
				throw new ArgumentNullException("xmlDoc", Resources.Rss_NullObjectError);

			var rss = new Feed();

			xmlReader.Read();

			if (xmlReader.NodeType == XmlNodeType.XmlDeclaration)
			{
				xmlReader.Read();
			}

			if (!xmlReader.Name.Equals(RssNode, StringComparison.CurrentCultureIgnoreCase))
				throw new FeedReadException("This is not an rss feed");

			try
			{
				rss.Version = (int)Convert.ToDouble(xmlReader.GetAttribute(VersionAttr));
			}
			catch (FormatException)
			{
				rss.Version = 2;
			}

			xmlReader.Read();

			if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name.Equals(ChannelNode, StringComparison.CurrentCultureIgnoreCase))
			{
				bool complete = false;

				while (!complete && xmlReader.Read())
				{
					string nodeName = xmlReader.Name.ToLower();

					switch (xmlReader.NodeType)
					{
						case XmlNodeType.Element:

							switch (nodeName)
							{
								case TitleNode:

									xmlReader.Read();
									rss.Title = xmlReader.Value;
									break;

								case LinkNode:

									xmlReader.Read();

									try
									{
										rss.Link = Web.UriBuilder.Create(xmlReader.Value);
									}
									catch (UriFormatException)
									{
										// swallow it
									}

									break;

								case DescriptionNode:

									xmlReader.Read();
									rss.Description = XmlSanitizer.StripHtml(xmlReader.Value);
									break;

								case PubDateNode:

									xmlReader.Read();
									rss.PublicationDate = new PublicationDate(xmlReader.Value).Date;
									break;

								case ItemNode:
									{
										Item newItem = Item.Create(xmlReader);

										if (newItem.Enclosure != null && newItem.Enclosure.Url != null)
										{
											rss.Items.Add(newItem);
										}

									}

									break;
							}
							break;

						case XmlNodeType.EndElement:

							complete = nodeName.Equals(ChannelNode, StringComparison.CurrentCultureIgnoreCase)
								|| nodeName.Equals(RssNode, StringComparison.CurrentCultureIgnoreCase);
							break;
					}
				}
			}

			// if pubdate is still null
			// look for most recent pub date 
			// in list of items...

			if (rss.PublicationDate == null || rss.PublicationDate == DateTime.MinValue)
			{
				rss.PublicationDate = rss.Items.MostRecentDate;
			}

			return rss;
		}

	}
}
